using System;
using System.Collections;
using System.ComponentModel;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;

namespace Core.Mapping
{
    [Serializable()]
    [DefaultProperty("TileZone")]
    [XmlRoot()]
    public class TileZone
    {
        public const int MapGridWidth = 5;
        public const int MapGridHeight = 5;
        /// <summary>Get/Set The Zones Name</summary>
        [CategoryAttribute("Zone"), DescriptionAttribute("Zone Name")]
        [XmlAttribute("Name")]
        public string Name { get { return _Name; } set { _Name = value; } }

        /// <summary>Array of Maps in Zone</summary>
        [XmlIgnore()]
        public Map[] Maps { get { return _Maps; } }

        /// <summary>Get/Set This Zones WorldCoordinate</summary>
        [XmlElement("WorldCoordinate")]
        public Point WorldCoordinate { get { return _WorldCoordinate; } set { _WorldCoordinate = value; } }

        /// <summary>Get Height of Zone in Tiles</summary>
        [CategoryAttribute("Zone"), DescriptionAttribute("Zone Height In Tiles")]
        [XmlAttribute("ZoneHeight")]
        public int ZoneHeight { get { return _ZoneHeight; } set { _ZoneHeight = value; } }

        /// <summary>Get Width of Zone in Tiles</summary>
        [CategoryAttribute("Zone"), DescriptionAttribute("Zone Width In Tiles")]
        [XmlAttribute("ZoneWidth")]
        public int ZoneWidth { get { return _ZoneWidth; } set { _ZoneWidth = value; } }

        [XmlIgnore()]
        public TileWorld ParentWorld { get { return _ParentWorld; } set { _ParentWorld = value; } }

        protected string _Name;
        protected Map[] _Maps = new Map[MapGridHeight * MapGridWidth];
        protected Point _WorldCoordinate;
        protected int _ZoneHeight;
        protected int _ZoneWidth;
        protected TileWorld _ParentWorld;

        public TileZone(string name, Point worldcoord, TileWorld ParentWorld)
        {
            _Name = name;
            _WorldCoordinate = worldcoord;
            _ParentWorld = ParentWorld;
            _ZoneHeight = 128 * MapGridWidth;
            _ZoneWidth = 128 * MapGridHeight;
        }

        public TileZone() { 
            //For XML
        }

        public ArrayList GetMapsForRectangle(Rectangle currentView)
        {
            //Holds maps that we find
            ArrayList maps = new ArrayList();
            //Create new rectangle with Zone Level Coordinates and not World Coordinates.
            Rectangle zoneRec = new Rectangle(currentView.X - _WorldCoordinate.X, currentView.Y - _WorldCoordinate.Y,
                currentView.Width, currentView.Height);

            //get x,y location of upperleft corner of map.
            int mx = (currentView.X / 128) * 128;
            int my = (currentView.Y / 128) * 128;

            //Get x,y location of the first map to pass back.
            int x = zoneRec.X / 128;
            int y = zoneRec.Y / 128;
            //Used to check if any other maps are going to be passed back
            int bottom = zoneRec.Bottom;
            int right = zoneRec.Right;

            //If our first map is in this zone
            if (x >= 0 && y >= 0)
            {
                //Add the map, if it's not null
                if (_Maps[x + y * MapGridWidth] == null)
                {
                    //Load map from file, then add it to collection
                    _ParentWorld.LoadMap(this, new Point(mx, my));
                }

                maps.Add(_Maps[x + y * MapGridWidth]);
            }

            //is bottom or right on this map, if not then return the only map we have so far.
            if (bottom > (_WorldCoordinate.X + _ZoneWidth) && right > (_WorldCoordinate.Y + _ZoneHeight))
                return maps;
            //If only bottom is still contained in the zone
            if (bottom >= 0 && bottom <= (_WorldCoordinate.Y + _ZoneHeight))
            {
                //The map we want is one more down in the y direction
                if (_Maps[x + (y + 1) * MapGridWidth] == null)
                {
                    //Load map from file, then add it to collection
                    _ParentWorld.LoadMap(this, new Point(mx, my + 128));
                }

                //Add the map to our collection
                maps.Add(_Maps[x + (y + 1) * MapGridWidth]);
            }

            if (right >= 0 && right <= (_WorldCoordinate.X + _ZoneWidth))
            {
                //The map we want to add is to the right, so x+1
                if (_Maps[(x + 1) + (y * MapGridWidth)] == null)
                {
                    //Load map from file, then add it to collection
                    _ParentWorld.LoadMap(this, new Point(mx + 128, my));
                }
                
                //Add the map we want to our collection,if it's not null
                maps.Add(_Maps[(x + 1) + (y * MapGridWidth)]);

            }

            //If both bottom and right were added, then that means the x+1, y+1 map should also be added.
            if (maps.Count == 3)
            {
                if (_Maps[(x + 1) + (y + 1) * MapGridWidth] == null)
                {
                    //Load map from file, then add it to collection
                    _ParentWorld.LoadMap(this, new Point(mx + 128, my + 128));
                }

                //Add the fourth map
                maps.Add(_Maps[(x + 1) + (y + 1) * MapGridWidth]);
            }

            return maps;
        }

        public bool IsCoordinateInZone(Point worldC)
        {
            if (worldC.X >= _WorldCoordinate.X && worldC.Y >= _WorldCoordinate.Y &&
                worldC.X < _WorldCoordinate.X + _ZoneWidth && worldC.Y < _WorldCoordinate.Y + _ZoneHeight)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        public static TileZone EmptyZone(TileWorld ParentWorld)
        {
            return new TileZone("Empty", new Point(), ParentWorld);
        }

        public static TileZone NewFullZone(Point WorldCoordinates, string Name, TileWorld ParentWorld)
        {
            TileZone tz = new TileZone(Name, WorldCoordinates, ParentWorld);

            tz._WorldCoordinate = WorldCoordinates;

            for (int x = 0; x < ParentWorld.ZoneGridWidth; x++)
            {
                for (int y = 0; y < ParentWorld.ZoneGridHeight; y++)
                {
                    tz.Maps[x + y * MapGridWidth] = Map.NewEmptyMap(WorldCoordinates.X + (128 * x), WorldCoordinates.Y + (128 * y));
                }
            }

            return tz;
        }
    }
}
